#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstring>
#include <vector>
#include "NetGraph.h"
using namespace std;

template <class T>
void random_partition(vector<T> &vec, vector<vector<T>> &groups)
{
    int n = groups.size();
    if (vec.size() < n)
    {
        cerr << "Error: Not enough elements to partition." << endl;
        exit(1);
    }
    // 打乱 vector 中的元素顺序
    shuffle(vec.begin(), vec.end(), default_random_engine(static_cast<unsigned int>(time(nullptr))));

    // 确保每组至少有1个元素
    for (int i = 0; i < n; ++i)
    {
        groups[i].push_back(vec[0]);
        vec.erase(vec.begin()); // 上一次erase之后，vec的size已经减小了
    }

    // 初始化随机数生成器
    default_random_engine rng(static_cast<unsigned int>(time(nullptr)));

    // 随机分配元素到组
    for (auto &element : vec)
    {
        // 生成一个随机的组索引
        int groupIndex = uniform_int_distribution<int>(0, n - 1)(rng);
        groups[groupIndex].push_back(element);
    }
}

void parse_config(string configFile, int &nVoltS, int &nCurrS, int &nR, int &nC, int &nL, int &nShort, int &nLoop, bool &bOpen)
{
    // default values
    nVoltS = nCurrS = nR = nC = nL = 0;
    nLoop = 1;
    nShort = 0;
    bOpen = false;

    // read config file
    ifstream infile(configFile);
    string line;
    while (getline(infile, line))
    {
        // read one line of config file
        string nameStr, numStr;
        istringstream iss(line);
        iss >> nameStr >> numStr;
        if (nameStr == "nVoltS")
            nVoltS = stoi(numStr);
        else if (nameStr == "nCurrS")
            nCurrS = stoi(numStr);
        else if (nameStr == "nR")
            nR = stoi(numStr);
        else if (nameStr == "nC")
            nC = stoi(numStr);
        else if (nameStr == "nL")
            nL = stoi(numStr);
        else if (nameStr == "nShort")
            nShort = stoi(numStr);
        else if (nameStr == "nLoop")
            nLoop = stoi(numStr);
        else if (nameStr == "bOpen")
            bOpen = bool(stoi(numStr));
    }
    infile.close();
    bool invalidInputFlag = nVoltS < 0 || nCurrS < 0 || nR < 0 || nC < 0 || nL < 0 || nShort < 0 || nLoop <= 0;
    if (invalidInputFlag)
    {
        throw runtime_error("Invalid input.");
    }
    // cout << "nVoltS: " << nVoltS << endl;
    // cout << "nCurrS: " << nCurrS << endl;
    // cout << "nR: " << nR << endl;
    // cout << "nC: " << nC << endl;
    // cout << "nL: " << nL << endl;
    // cout << "nShort: " << nShort << endl;
    // cout << "nLoop: " << nLoop << endl;
    // cout << "bOpen: " << bOpen << endl;
}

// 对所有网表中的节点重新编号，在保留GND的前提下使得节点id不重复
void resort_nodes(vector<NetGraph *> &nets)
{
    int id = 1;
    for (auto &net : nets)
    {
        for (auto &node : net->get_nodes())
        {
            if (node->id != 0)
                node->id = id++;
        }
    }
}

vector<NetGraph *> generate_netlist(int nVoltS, int nCurrS, int nR, int nC, int nL, int nShort, int nLoop, bool bOpen)
{
    // 1. create components
    // 首先检查输入，非法输入报错
    if (nVoltS < 0 || nCurrS < 0 || nR < 0 || nC < 0 || nL < 0 || nShort < 0 || nLoop <= 0)
    {
        cerr << "Error: Invalid input: Arguments must be non-negative and nLoop must be positive." << endl;
        exit(1);
    }
    else if (nVoltS > 1e6 || nCurrS > 1e6 || nR > 1e6 || nC > 1e6 || nL > 1e6 || nLoop > 1e4)
    {
        cerr << "Error: Invalid input: Inputs are too large." << endl;
        exit(1);
    }
    if (nVoltS + nCurrS < nLoop)
    {
        cerr << "Error: Invalid input: Not enough sources." << endl;
        exit(1);
    }
    if (nR + nC + nL < nLoop)
    {
        cerr << "Error: Invalid input: Not enough passive components." << endl;
        exit(1);
    }
    if (nShort > nVoltS)
    {
        cerr << "Error: Invalid input: Too many shorts." << endl;
        exit(1);
    }
    else if (nShort == nVoltS && nCurrS == 0 && bOpen == true)
    {
        cerr << "Error: Invalid input: Sources are all shorted, cannot be open circuit the same time." << endl;
        exit(1);
    }
    vector<Component *> componentsActive;  // 有源器件
    vector<Component *> componentsPassive; // 无源器件
    random_device rd;
    mt19937 gen(rd());

    uniform_real_distribution<double> value_dis(0, 100);

    // 创建有源器件
    for (int i = 0; i < nVoltS; i++)
    {
        Component *c;
        // 标记短路
        if (i < nShort)
        {
            c = new Component("V" + to_string(i + 1), Component::Type::VS, value_dis(gen));
            c->set_shorted(true);
        }
        else
            c = new Component("V" + to_string(i + 1), Component::Type::VS, value_dis(gen));
        componentsActive.push_back(c);
    }
    for (int i = 0; i < nCurrS; i++)
    {
        Component *c = new Component("I" + to_string(i + 1), Component::Type::CS, value_dis(gen));
        componentsActive.push_back(c);
    }

    // 标记开路
    if (bOpen)
    {
        uniform_int_distribution<> dis(0, componentsActive.size() - 1);

        Component *selectedComponent = nullptr;

        // 循环直到选到一个未被短路的有源器件
        while (selectedComponent == nullptr || selectedComponent->is_shorted())
        {
            int randomIndex = dis(gen);
            selectedComponent = componentsActive[randomIndex];
        }

        // 置为开路
        selectedComponent->set_open(true);
    }

    // 创建无源器件
    for (int i = 0; i < nR; i++)
    {
        Component *c = new Component("R" + to_string(i + 1), Component::Type::R, value_dis(gen));
        componentsPassive.push_back(c);
    }
    for (int i = 0; i < nC; i++)
    {
        Component *c = new Component("C" + to_string(i + 1), Component::Type::C, value_dis(gen));
        componentsPassive.push_back(c);
    }
    for (int i = 0; i < nL; i++)
    {
        Component *c = new Component("L" + to_string(i + 1), Component::Type::L, value_dis(gen));
        componentsPassive.push_back(c);
    }

    // 2. divide components into groups
    vector<vector<Component *>> groups(nLoop);
    random_partition(componentsActive, groups);
    random_partition(componentsPassive, groups);
    // 输出分组结果
    // for (int i = 0; i < groups.size(); i++)
    // {
    //     cout << "Group " << i + 1 << ": ";
    //     for (auto &component : groups[i])
    //         cout << component->get_name() << " ";
    //     cout << endl;
    // }

    // 3. create loops
    vector<NetGraph *> nets;
    for (int i = 0; i < nLoop; i++)
    {
        NetGraph *net = new NetGraph(groups[i], i);
        nets.push_back(net);
    }

    // 4. resort nodes
    resort_nodes(nets);

    return nets;
}

int main()
{
    int nVoltS, nCurrS, nR, nC, nL, nShort, nLoop;
    bool bOpen;
    // default values
    nVoltS = nCurrS = nR = nC = nL = 0;
    nLoop = 1;
    nShort = 0;
    bOpen = false;
    // parse config file
    try
    {
        parse_config("../test/netlistConfig.txt", nVoltS, nCurrS, nR, nC, nL, nShort, nLoop, bOpen);
        // generate netlist
        vector<NetGraph *> nets = generate_netlist(nVoltS, nCurrS, nR, nC, nL, nShort, nLoop, bOpen);
        ofstream outfile("../test/netlistDump.sp"); // 打开文件流
        if (outfile.is_open())              // 检查文件是否成功打开
        {
            for (int i = 0; i < nets.size(); i++)
            {
                nets[i]->print_netlist(outfile); // 将网表输出到文件
            }
            outfile.close(); // 关闭文件流
        }
        else
        {
            cerr << "Unable to open file netlistDump.sp"; // 如果文件未成功打开，输出错误信息
        }
        for (int i = 0; i < nets.size(); i++)
            delete nets[i]; // 释放内存
    }
    catch (const exception &e)
    {
        cerr << "Error: " << e.what() << endl;
        exit(1);
    }

    return 0;
}